package com.thz.system.utils.pdf;

import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import com.thz.system.config.DocumentConverterProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 基于 LibreOffice 的文档转换工具
 */
@Slf4j
@Component
public class LibreOfficeConverter {

    private final DocumentConverterProperties properties;

    public LibreOfficeConverter(DocumentConverterProperties properties) {
        this.properties = properties;
    }

    /**
     * 使用 LibreOffice 将文档转换为 PDF
     *
     * @param inputFile      输入文件
     * @param convertToParam 转换参数，例如 pdf:writer_pdf_Export:SelectPdfVersion=1
     * @return 输出 PDF 文件
     */
    public File convertToPdf(File inputFile, String convertToParam) {
        if (inputFile == null || !inputFile.exists()) {
            throw new BusinessException(ErrorCode.FILE_NOT_FOUND, "输入文件不存在");
        }

        if (!properties.isLibreOfficeConfigured()) {
            throw new BusinessException(ErrorCode.LIBREOFFICE_NOT_CONFIGURED);
        }

        String convertTarget = (convertToParam == null || convertToParam.isBlank())
                ? "pdf:writer_pdf_Export"
                : convertToParam;

        List<String> command = new ArrayList<>();
        command.add(properties.getLibreofficePath());
        command.add("--headless");
        command.add("--nologo");
        command.add("--nofirststartwizard");
        command.add("--convert-to");
        command.add(convertTarget);
        command.add("--outdir");
        command.add(inputFile.getParentFile().getAbsolutePath());
        command.add(inputFile.getAbsolutePath());

        log.info("执行LibreOffice转换: {}", String.join(" ", command));

        Process process = null;
        String stderr = "";
        try {
            ProcessBuilder builder = new ProcessBuilder(command);
            builder.redirectErrorStream(true);
            process = builder.start();

            stderr = readProcessOutput(process.getInputStream());

            boolean finished = process.waitFor(properties.getTimeoutSeconds(), TimeUnit.SECONDS);
            if (!finished) {
                process.destroyForcibly();
                throw new BusinessException(ErrorCode.DOCUMENT_CONVERT_TIMEOUT);
            }

            int exitCode = process.exitValue();
            if (exitCode != 0) {
                log.error("LibreOffice执行失败，exitCode={}, stderr={}", exitCode, stderr);
                throw new BusinessException(ErrorCode.LIBREOFFICE_EXECUTION_FAILED,
                        "LibreOffice执行失败: " + stderr);
            }

            File pdfFile = locatePdfOutput(inputFile);
            if (pdfFile == null || !pdfFile.exists()) {
                throw new BusinessException(ErrorCode.CONVERSION_FAILED, "未找到PDF输出文件");
            }
            return pdfFile;
        } catch (IOException e) {
            log.error("启动LibreOffice失败", e);
            throw new BusinessException(ErrorCode.LIBREOFFICE_EXECUTION_FAILED, e.getMessage(), e);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException(ErrorCode.DOCUMENT_CONVERT_TIMEOUT, e.getMessage(), e);
        } finally {
            if (process != null && process.isAlive()) {
                process.destroyForcibly();
            }
        }
    }

    private File locatePdfOutput(File inputFile) {
        String baseName = stripExtension(inputFile.getName());
        File candidate = new File(inputFile.getParentFile(), baseName + ".pdf");
        if (candidate.exists()) {
            return candidate;
        }
        File[] pdfFiles = inputFile.getParentFile().listFiles(f ->
                f.isFile() && f.getName().toLowerCase().endsWith(".pdf"));
        if (pdfFiles == null || pdfFiles.length == 0) {
            return null;
        }
        // 选择最新修改的文件
        return java.util.Arrays.stream(pdfFiles)
                .filter(File::exists)
                .max(Comparator.comparingLong(File::lastModified))
                .orElse(null);
    }

    private String stripExtension(String filename) {
        if (filename == null || filename.isEmpty()) {
            return "";
        }
        int pos = filename.lastIndexOf('.');
        if (pos > 0) {
            return filename.substring(0, pos);
        }
        return filename;
    }

    private String readProcessOutput(InputStream inputStream) throws IOException {
        StringBuilder builder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line).append(System.lineSeparator());
            }
        }
        return builder.toString();
    }
}

